0%

SpringAI — Advisors(顾问模式)

概述

Spring AI 的 Advisors API 提供了一种灵活而强大的方式,用于在 Spring 应用中拦截、修改和增强 AI 驱动的交互。通过 Advisors API,开发者可以构建更复杂、可复用且易维护的 AI 组件。

主要优势:

  • 封装常见的生成式 AI 模式(如 RAG、对话记忆、内容审查等)
  • 转换发送给和接收自大语言模型(LLM)的数据
  • 在不同模型和用例之间实现可移植性

推荐注册方式:官方建议在构建时使用 ChatClientdefaultAdvisors() 方法注册 Advisor:

1
2
3
ChatClient.builder(chatModel)
.defaultAdvisors(new MyAdvisor())
.build();

同时Advisor 也会加入 Observability(可观测性)栈,你可以查看其执行的指标(Metrics)和链路追踪(Traces)。

核心组件

API 包含以下核心接口和类:

组件 说明
CallAdvisor / CallAdvisorChain 非流式(同步)场景
StreamAdvisor / StreamAdvisorChain 流式(响应式)场景
ChatClientRequest 表示未封包的 Prompt 请求
ChatClientResponse 表示 Chat Completion 响应

二者都持有 advise-context,用于在 Advisor 链中共享状态。

springai-advisors-components

关键方法

  • adviseCall() —— 非流式 Advisor 的核心方法
  • adviseStream() —— 流式 Advisor 的核心方法

这些方法通常执行以下操作:

  1. 检查未封包的 Prompt 数据
  2. 自定义和增强 Prompt 数据
  3. 调用链中的下一个实体
  4. 可选:阻断请求(不调用下一个实体)
  5. 检查 Chat Completion 响应
  6. 抛出异常以指示处理错误

此外:

  • getOrder() —— 决定 Advisor 在链中的执行顺序
  • getName() —— 提供唯一的 Advisor 名称

Advisor 链的执行流程

Spring AI 框架advisor和聊天模型之间的交互流程如下:
springai-advisor-chain-invoke

  1. 根据用户 Prompt 创建 ChatClientRequest,并初始化一个空的 advisor context
  2. 链中每个 Advisor 依次处理请求(可修改请求,也可选择不调用下一个实体从而阻断请求——此时 Advisor 需自行填充响应)
  3. 框架自动添加的最后一个 Advisor 将请求发送给 Chat Model
  4. Chat Model 的响应沿 Advisor 链反向传回,转换为 ChatClientResponse(包含共享的 context)
  5. 每个 Advisor 可处理或修改响应
  6. 最终 ChatClientResponse 被返回给调用方

执行顺序(Order)

执行顺序由 getOrder() 方法控制,遵循 Spring Ordered 接口的语义:

  • order 值越小,优先级越高,越先执行(请求阶段),越后执行(响应阶段)
  • Advisor 链表现为栈(Stack)结构
    • 第一个入栈的 Advisor → 最先处理请求(栈展开时)
    • 同一个 Advisor → 最后处理响应(栈回退时)
  • 顺序控制
    • Ordered.HIGHEST_PRECEDENCE,以确保顾问在链中首先执行(请求处理首先执行,响应处理最后执行)
    • Ordered.LOWEST_PRECEDENCE,以确保顾问程序在链中最后执行(请求处理最后执行,响应处理最先执行)。

⚠️ 相同 order 值时不保证执行顺序。

如果需要在请求和响应端都位于顾问链首位,建议如下:

  1. 拆分为两个独立的 Advisor
  2. 分别配置不同的 order 值
  3. 通过 advisor context 在它们之间共享状态

自定义 Advisor

要实现自定义 Advisor,需实现 CallAdvisorStreamAdvisor(或两者都实现):

  • 非流式核心方法:nextCall(CallAdvisorChain chain, ChatClientRequest request)
  • 流式核心方法:nextStream(StreamAdvisorChain chain, ChatClientRequest request)

Logging Advisor 示意

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {

private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);

@Override
public String getName() {
return this.getClass().getSimpleName();
}

@Override
public int getOrder() {
return 0;
}


@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
logRequest(chatClientRequest);

ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(chatClientRequest);

logResponse(chatClientResponse);

return chatClientResponse;
}

@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest,
StreamAdvisorChain streamAdvisorChain) {
logRequest(chatClientRequest);

Flux<ChatClientResponse> chatClientResponses = streamAdvisorChain.nextStream(chatClientRequest);

return new ChatClientMessageAggregator().aggregateChatClientResponse(chatClientResponses, this::logResponse);
}

private void logRequest(ChatClientRequest request) {
logger.debug("request: {}", request);
}

private void logResponse(ChatClientResponse chatClientResponse) {
logger.debug("response: {}", chatClientResponse);
}

}

内置 Advisor

Spring AI 框架提供了多个内置 Advisor 来增强与AI 交互:

对话记忆 Advisor

Advisor 说明
MessageChatMemoryAdvisor 从对话记忆存储中检索历史消息,作为消息集合加入 Prompt,保留对话结构。注意:并非所有 AI 模型都支持此方式。
VectorStoreChatMemoryAdvisor VectorStore 检索记忆,注入到 Prompt 的 system text 中。适合从大规模数据集中高效搜索和检索相关信息。

RAG(检索增强生成)Advisor

Advisor 说明
QuestionAnswerAdvisor 使用向量存储提供问答能力,实现 Naive RAG 模式。
RetrievalAugmentationAdvisor 使用 org.springframework.ai.rag 包中定义的构建块实现常见的 RAG 流程,遵循模块化 RAG 架构。

其他 Advisor

Advisor 说明
ReReadingAdvisor 实现 RE2 重读策略,在输入阶段增强 LLM 的理解能力。基于论文:Re-Reading Improves Reasoning in LLMs
ToolCallingAdvisor 处理 Tool Calling 循环。该 Advisor 始终由 ChatClient 自动注册(除非被显式禁用),支持运行时由其他 Advisor 注入工具。实现 ToolAdvisor 标记接口,防止第二个 ToolCallingAdvisor 被自动注册。
SafeGuardAdvisor 简单的内容安全 Advisor,用于防止模型生成有害或不恰当的内容。

最佳实践

  • ✅ 保持每个 Advisor 职责单一,提升模块化程度
  • ✅ 必要时通过 adviseContext / updateContext() 在 Advisor 间共享状态
  • ✅ 尽量同时实现流式和非流式版本,以获得最大灵活性
  • ✅ 仔细规划 Advisor 的 getOrder() 值,确保数据流转正确